<?php

namespace Yiru\LaravelComposer\Console\Commands;

use Illuminate\Support\Str;
use Illuminate\Support\Arr;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Auth;
use Log;
use DB;
use Exception;

use Symfony\Component\Console\Input\InputOption;

use Josh\Terminal\TerminalFacade    as Terminal;
use mikehaertl\shellcommand\Command as Shell;               //https://github.com/mikehaertl/php-shellcommand
use October\Rain\Config\DataWriter\Rewrite as Config;
use Webimpress\SafeWriter\FileWriter;

class ComposerInstall extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'composer:install {pkgs}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'install composer package for laravel';

    private $pacakge;

    public function __construct()
    {
        parent::__construct();
        // if(!class_exists('Shell')){
        //     exec('composer require mikehaertl/php-shellcommand -vvv',$out);
        //     var_dump($out);

        //     throw new Exception('mikehaertl\shellcommand\Command not install');            
        // }
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $pkgs = $this->argument('pkgs')?:null;
        if($pkgs=='all'){
            [$pkgs,$configs] = Arr::divide(config('composer'));
        }else $pkgs = explode(',',$pkgs);
        echo PHP_EOL;    
        foreach ($pkgs as $pkg) {
             echo $pkg.PHP_EOL;
        }
        echo PHP_EOL;    

        $this->repo($pkgs);
        $this->require($pkgs);
        $this->publish($pkgs);        
        $this->config($pkgs);
        $this->env($pkgs);
        $this->dependency($pkgs);
        // if(!empty($pkgs))        
    }

    protected function  shell($shell,$msg){
        if($shell->execute()){
            $ret=$shell->getOutput(); 
            $this->output->success($ret);  
        }else{
            $ret=$shell->getError();
            $this->output->error($ret);  
            $exitCode = $shell->getExitCode();
            throw new Exception($msg);
        }    
    }
    /// 本地文件包仓库
    // {
    //     "type": "path",
    //     "url": "../packages/*/*",
    //     "options": {
    //       "symlink": true
    //     }   
    // },   
     /**
     * Composer Require package
     *
     * @return bool
     */
    public function repo($pkgs){
        $reqPkgs="";
        if(!is_array($pkgs)) $pkgs=[$pkgs];
        foreach ($pkgs as $pkg) {
            $repo=config('composer.'.$pkg.'.repo');
            if(empty($repo)) continue;
            $command  ='composer config  repositories.'.Str::of($pkg)->replace('/', '_');
            $argument ='--json \''.json_encode($repo).'\'';
            $shell= new Shell($command.' '.$argument);

            $this->shell($shell,"composer config repositories");
        }     
    }

    /**
     * Composer Require package
     * @return bool
     */
    public function require($pkgs)
    {
        $reqPkgs="";
        if(!is_array($pkgs)) $pkgs=[$pkgs];
        foreach ($pkgs as $pkg) {
            $ver=config('composer.'.$pkg.'.ver');
            echo PHP_EOL.$pkg.' ver:'.$ver;
            if(!empty($ver))$pkg = Str::of($pkg)->append(':'.$ver);
            // $pkg    = Str::of($pkg)->append(config('composer.'.$pkg.'.ver'));            
            $reqPkgs= Str::of($reqPkgs)->append(" ".$pkg);
            echo PHP_EOL.$pkg;
        }
        $this->output->note('composer require -vvv '.$reqPkgs);
        $shell= new Shell('composer require -vvv '.$reqPkgs);
        $this->shell($shell,"composer require");

        $shell= new Shell('composer dumpautoload');
        $this->shell($shell,"composer dumpautoload");
    }

    /**
     * Publish package
     * @return bool
     */
    public function publish($pkgs)
    {
        if(!is_array($pkgs)) $pkgs=[$pkgs];
        foreach ($pkgs as $pkg) {
            // $this->output->title($pkg);
            $providers=config('composer.'.$pkg.'.publish.provider');
            $tags     =config('composer.'.$pkg.'.publish.tag');
            $pres     =config('composer.'.$pkg.'.publish.pre');
            $providerCmd='';
            $this->output->note($pkg.':'.$providers);
            if(!empty($pres))  {
                if(!is_array($pres)) $pres=[$pres];
                foreach ($pres as $pre) {
                    $this->output->note($pkg.' pre '.$pre);
                    $shell= new Shell($pre);
                    $this->shell($shell,"$pkg pre failed");
                }                
            }
            if(!empty($providers))  {
                if(!is_array($providers)) $providers=[$providers];
                foreach ($providers as $provider) {
                    $this->output->note('php artisan vendor:publish --provider="'.$provider.'" --force ');
                    $shell=new Shell('php artisan vendor:publish --provider="'.$provider.'" --force ');
                    $this->shell($shell,"$pkg vendor:publish failed");
                }
                
                $providerCmd='--provider="'.$provider.'"';
            }
            if(!empty($tags)) {
                if(!is_array($tags)) $tags=[$tags];
                foreach ($tags as $tag) {
                    $this->output->note('php artisan vendor:publish --tag="'.$tag.'" '.$providerCmd);
                    $shell=new Shell('php artisan vendor:publish --tag="'.$tag.'" '.$providerCmd);    
                    $this->shell($shell,"$pkg vendor:publish ".$tag.' failed');   
                }                
            }            
        }
    }

    /**
     * migrations package, 
     * Check config/package.{package}.table, if table exist, do nothing 
     * otherwise migration, 
     * @return bool
     */
    public function migrations($pkg)
    {
        
            
            
    }

    /**
     * package, 
     * Check config/package.{package}.table, if table exist, do nothing 
     * otherwise migration, 
     * @return bool
     */
    public function view($pkg)
    {
        
            
            
    }

    /**
     * package, 安装命令
     * Check config/package.{package}.dependency, if table exist, do nothing 
     * otherwise migration, 
     * @return bool
     */
    public function dependency($pkgs)
    {
        
        if(!is_array($pkgs)) $pkgs=[$pkgs];
        foreach ($pkgs as $pkg) {
            $items=config('composer.'.$pkg.'.dependency');
            if(!empty($items)){
                echo PHP_EOL.'install dependency for '.$pkg.PHP_EOL;
                foreach ($items as $item ) {    
                    echo "installing...".$item; 
                    if(empty($item))continue;
                    $shell=new Shell($item);
                    $this->shell($shell,"Install failed");
                }
            }
        }            
    }
    /**
     * env配置
     * 配置env的环境变量     
     * @return bool
     */
    public function env($pkgs)
    {
        
       if(!is_array($pkgs)) $pkgs=[$pkgs];
        foreach ($pkgs as $pkg) {
            $envItems=config('composer.'.$pkg.'.env');
            if(!empty($envItems)){
                echo PHP_EOL.'env for '.$pkg.PHP_EOL;
                foreach ($envItems as $key => $value) {
                    if(empty($value)) continue;                    
                    dump('php artisan dotenv:set-key '.$key.' '.$value.' '.'"for '.$pkg.'"');
                    $shell=new Shell('php artisan dotenv:set-key '.$key.' '.$value.' '.'"for '.$pkg.'"');
                    $this->shell($shell,"env set failed");
                }
            }
        }
        $shell=new Shell('php artisan config:cache');    
        $this->shell($shell,"config:cache failed");
    }
    /**
     * Config  package， 
     * Check config/package.{package}.config, if config item update config/XXX.XXXX
     * @return bool
     */
    public function config($pkgs)
    {
        if(!is_array($pkgs)) $pkgs=[$pkgs];
        foreach ($pkgs as $pkg) {
            $configItems=config('composer.'.$pkg.'.config');
            if(!empty($configItems)){
                foreach ($configItems as $file => $items) {                    
                    $config=include(config_path($file.'.php'));   
                    echo PHP_EOL.'config file:'.config_path($file.'.php').PHP_EOL;
                    foreach (Arr::dot($items) as $item => $value){                         
                        if(Arr::get($config,$item,'NOSET')==='NOSET') {
                            $this->output->error(config_path($file.'.php.').$item.' not exist');
                            continue;
                            Arr::set($config,$item,$value);
                            $content = "<?php\nreturn " . var_export($config, true) . ';';
                            FileWriter::writeFile(config_path($file.'1.php'), $content);    
                        }else{

                        }
                    }                    
                    dump(Arr::dot($items));
                    dump($file);
                    (new Config)->toFile(config_path($file.'.php'),Arr::dot($items));
                }
                $this->output->note('update '.$pkg.".config to:".config_path($file.'.php'));
            }
        }
        $shell=new Shell('php artisan config:cache');    
        $this->shell($shell,"update config file failed");
    }

    protected function getOptions()
    {
        return [
            ['c', 'c', InputOption::VALUE_OPTIONAL, 'Connection name'],
        ];
    }

}